package util.nlp;

import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;

import util.hashing.HashOperations;
import util.io.FileInput;
import util.parser.GenericEntryParser;

public class WikiCategoryNavigator {

	/**
	 * @param args
	 */

	private HashDictionary categories_dict = null;
	private HashDictionary categories_expanded = null;

	private HashDictionary stop_categories = null;

	/**
	 * 
	 * 
	 * 
	 * @param path
	 *            Path file with the categories format WikipageTitle Category1
	 *            Category2
	 * @param id
	 * @param categories
	 */

	public WikiCategoryNavigator(String path, int id, int categ[], String SEP,
			String DEL, String SEP2) {

		categories_dict = new HashDictionary(path, DEL, SEP, SEP, 1, categ);

	}

	public WikiCategoryNavigator(String path, String expandedPath, int id,
			int categ[], String SEP, String DEL, String SEP2) {

		categories_dict = new HashDictionary(path, DEL, SEP, SEP, 1, categ);

		int values[] = { 1, 2, 3 };
		categories_expanded = new HashDictionary(expandedPath, DEL, SEP, 0,
				values);

	}

	public void iniStopCategories(String path) {

		stop_categories = new HashDictionary(path);

	}

	public void iniExpandedCategories(String path) {

		categories_expanded = new HashDictionary(path);

	}

	/*
	 * private void expandCategory(String wikiCategory, int level, int
	 * current_level, Hashtable<String, Integer> categories, boolean levelOn) {
	 * 
	 * if (categories.containsKey(wikiCategory)) { if (levelOn) {
	 * categories.put(wikiCategory, current_level); }
	 * 
	 * else {
	 * 
	 * categories.put(wikiCategory, categories.get(wikiCategory) + 1); } } else
	 * {
	 * 
	 * if (levelOn) { categories.put(wikiCategory, current_level); }
	 * 
	 * else {
	 * 
	 * categories.put(wikiCategory, 1); }
	 * 
	 * }
	 * 
	 * if (level > 0) {
	 * 
	 * level--; current_level++; if (categories_dict.containsKey(wikiCategory))
	 * {
	 * 
	 * LinkedList<String> parent_categories = categories_dict
	 * .getEntries(wikiCategory); for (int i = 0; i < parent_categories.size();
	 * i++) { expandCategory(parent_categories.get(i), level, current_level,
	 * categories, levelOn);
	 * 
	 * }
	 * 
	 * }
	 * 
	 * }
	 * 
	 * }
	 */
	private void expandCategory(String wikiCategory, int level,
			Integer current_level,
			Hashtable<Integer, LinkedList<String>> categories) {

		if (categories.containsKey(current_level)) {

			categories.get(current_level).add(wikiCategory);
		}

		else {

			LinkedList<String> list = new LinkedList<String>();
			list.add(wikiCategory);
			categories.put(current_level, list);
		}

		if (level > 0) {
			// System.out.println("Recursion:" + level + "\t" + wikiCategory) ;
			level--;
			current_level++;
			if (categories_dict.containsKey(wikiCategory)) {

				LinkedList<String> parent_categories = categories_dict
						.getEntries(wikiCategory);
				for (int i = 0; i < parent_categories.size(); i++) {
					expandCategory(parent_categories.get(i), level,
							current_level, categories);

				}

			}

		}

	}

	private Hashtable<Integer, LinkedList<String>> expandCategories(
			String string, String cat, boolean b, int deep) {
		// TODO Auto-generated method stub
		Hashtable<Integer, LinkedList<String>> categories = new Hashtable<Integer, LinkedList<String>>();

		String current_categories[] = cat.split("\t");

		for (int i = 0; i < current_categories.length; i++) {
			expandCategory(current_categories[i], deep, 0, categories);

		}

		return categories;
	}

	public Hashtable<Integer, LinkedList<String>> expandCategories(
			String wikipage, boolean levelOn, int level) {

		Hashtable<Integer, LinkedList<String>> categories = new Hashtable<Integer, LinkedList<String>>();

		LinkedList<String> parent_categories = categories_dict
				.getEntries(wikipage);
		for (int i = 0; i < parent_categories.size(); i++) {
			expandCategory(parent_categories.get(i), level, 0, categories);

		}

		return categories;
	}

	public void expandCategoriesFile(String path, String SEP, String DEL,
			int deep) {

		FileInput in = new FileInput(path);

		String line = in.readString();

		while (line != null) {

			String t[] = GenericEntryParser.parseEntry(line, SEP, DEL);

			Hashtable<Integer, LinkedList<String>> hash = expandCategories(
					t[1], t[2], false, deep);
			System.out.println(hash.size());
			if (hash != null) {

				for (int j = 2; j < deep; j++) {

					if (hash.containsKey(j)) {
						LinkedList<String> list = hash.get(j);

						String tmp = "\"";

						if (list != null && list.size() > 0) {

							tmp = tmp + list.get(0);
						}
						for (int i = 1; i < list.size(); i++) {

							tmp = tmp + "\t" + list.get(i);
						}
						// System.out.println("----" + j + "\t" + list.size() +
						// "\t" + tmp);

						tmp = tmp + "\"";

						line = line + "\t" + tmp;

					} else {
						line = line + "\t\"\"";
					}
				}

			}
			System.out.println(line);
			line = in.readString();
		}

	}

	public void expandCategoriesTemplates(String path, String SEP, String DEL,
			int deep) {

		FileInput in = new FileInput(path);

		String line = in.readString();
		StringBuffer line_buffer = null;
		int counter = 0;
		
		int limit = 6204924;
		while (line != null) {

			if (counter > limit) {

				line_buffer = new StringBuffer(line);
				String t[] = GenericEntryParser.parseEntry(line_buffer
						.toString(), SEP, DEL);
				// System.out.println(line);

				// Expand categories position 2
				for (int i = 0; i < deep; i++) {

					String cat[] = t[2].split("\t");

					String expanded = findFatherOfCategories(cat, i + 1);
					// System.out.println(line);
					line_buffer.append("\t" + "\"" + expanded + "\"");
					// System.out.println(line);
				}

				// Expand templates position 3

				String categories_templates = fetchCategories(t[3].split("\t"));

				line_buffer.append("\t" + "\"" + categories_templates + "\"");

				for (int i = 0; i < deep; i++) {

					String cat[] = categories_templates.split("\t");

					String expanded = findFatherOfCategories(cat, i + 1);
					line_buffer.append("\t" + "\"" + expanded + "\"");

				}
				System.out.println(line_buffer.toString());
				// Expand wikis position 4

				// System.out.println(line);

			}
			line = in.readString();
			counter++;
		}

	}

	private String fetchCategories(String[] tem) {
		// TODO Auto-generated method stub
		StringBuffer categories = new StringBuffer("");

		for (int i = 0; i < tem.length; i++) {

			LinkedList<String> list = categories_dict.getEntries(tem[i]);

			for (int j = 0; list != null && j < list.size(); j++) {

				categories.append(list.get(j) + "\t");

			}

		}

		String cat = categories.toString();
		if (cat.endsWith("\t"))
			cat = cat.substring(0, categories.length() - 1);

		return cat;
	}

	public String findFatherOfCategories(String categories[], int level) {

		LinkedList<String> list = new LinkedList<String>();

		for (int i = 0; categories != null && i < categories.length && list.size() < 300; i++) {

			if (categories_expanded.containsKey(categories[i])) {
				// System.out.println(":found!----");

				LinkedList<String> temp = categories_expanded
						.getEntries(categories[i]);

				// System.out.println(temp.size()+ "   " + "\t" + level + "\t"
				// );
				if (temp.size() >= level && level > 0) {

					String t = temp.get(level - 1);
					String cat_at_level[] = t.split("\t");

					for (int j = 0; j < cat_at_level.length && list.size()<300; j++) {
						if (!cat_at_level[j].equals("")) {
							list.add(cat_at_level[j]);

							// System.out.println(":" + cat_at_level[j]);

						}

					}

				}

			}

			// System.out.println("");

		}

		StringBuffer line = new StringBuffer("");

		if (list.size() > 1)
			line.append(list.get(0));
		for (int i = 1; i < list.size(); i++) {

			line.append("\t" + list.get(i));

		}

		list.clear();

		// System.out.println(line);
		return line.toString();

	}

	// temporal function to output category entries in a text file
	public static void createCategoryDictionary(String path) {
		FileInput in = new FileInput(path);

		String line = in.readString();
		String DEL = "\"";
		String SEP = "\t";
		while (line != null) {

			String t[] = GenericEntryParser.parseEntry(line, "\t", "\"");

			// System.out.println(line);

			if (t[1].startsWith("Category")
					|| t[1].toLowerCase().startsWith("template:"))
				System.out.println(DEL + t[0] + DEL + SEP + DEL + t[1] + DEL
						+ SEP + DEL + t[2] + DEL);

			// System.out.println("---" + line);
			line = in.readString();
		}

	}

	/**
	 * 
	 * 
	 * 
	 * @param seeds
	 * @param path
	 * @param pos
	 */
	public void generateCategoryBlackList() {

		String target = "Category:Wikipedia_administration";
		String stop = "Category:Contents";

		HashDictionary inverse = new HashDictionary(categories_dict);

		/*
		 * Enumeration<String> keys = categories_dict.getKeys();
		 * 
		 * while (keys.hasMoreElements()) {
		 * 
		 * String key = keys.nextElement();
		 * 
		 * LinkedList<String> list = categories_dict.getEntries(key);
		 * System.out.println("Explorarndo: " + key); boolean flag = false; for
		 * (int i = 0; !flag && i < list.size(); i++) {
		 * 
		 * if (isDescendentOf(list.get(i), target, stop)) {
		 * 
		 * System.out.println(key); flag = true; } else {
		 * 
		 * }
		 * 
		 * }
		 * 
		 * }
		 */

		LinkedList<String> list = inverse.getEntries(target);

		// for (int i = 0; i < list.size(); i++) {
		//
		// System.out.println(list.get(i));
		// }
		printDescendents(inverse, target, 3, 0);
	}

	public void generateCategoryExpandedList(int level) {

		Enumeration<String> keys = categories_dict.getKeys();

		while (keys.hasMoreElements()) {

			String key = keys.nextElement();
			Hashtable<Integer, LinkedList<String>> hash = new Hashtable<Integer, LinkedList<String>>();

			expandCategory(key, level, 0, hash);
			String line = "\"" + key + "\"";
			for (int j = 1; j < level + 1; j++) {

				if (hash.containsKey(j)) {
					LinkedList<String> list = hash.get(j);

					String tmp = "\"";

					if (list != null && list.size() > 0) {

						tmp = tmp + list.get(0);
					}
					for (int i = 1; i < list.size(); i++) {

						tmp = tmp + "\t" + list.get(i);
					}
					// System.out.println("----" + j + "\t" + list.size() +
					// "\t" + tmp);

					tmp = tmp + "\"";

					line = line + "\t" + tmp;

				} else {
					line = line + "\t" + "\"\"";
				}

			}

			System.out.println(line);
		}

	}

	public void printDescendents(HashDictionary d, String seed, int level,
			int current) {
		System.out.println(seed);

		if (d.containsKey(seed)) {

			LinkedList<String> list = d.getEntries(seed);

			for (int i = 0; i < list.size(); i++) {

				// System.out.println(list.get(i));

				if (current < level) {

					printDescendents(d, list.get(i), level, current + 1);

				}
			}

		} else {
			// System.out.println(seed + "-------------------------------");

		}

	}

	public boolean isDescendentOf(String child, String target, String stop) {

		LinkedList<String> parents = categories_dict.getEntries(child);

		if (child.equals(stop))
			return false;

		if (child.equals(target)) {

			return true;
		}

		for (int i = 0; parents != null && i < parents.size(); i++) {
			if (isDescendentOf(parents.get(i), target, stop)) {
				return true;
			}
		}

		return false;

	}

	/**
	 * 
	 * 
	 * @param path
	 */
	public static void printCategoryList(String path) {
		FileInput in = new FileInput(path);

		String line = in.readString();
		String DEL = "\"";
		String SEP = "\t";
		while (line != null) {

			String t[] = GenericEntryParser.parseEntry(line, "\t", "\"");

			String tt[] = t[2].split("\t");

			for (int i = 0; i < tt.length; i++)
				if (tt[i].startsWith("Category"))
					System.out.println(tt[i]);

			// System.out.println("---" + line);
			line = in.readString();
		}

	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String wiki = "Dunn_(bishop)";

		String path = "/media/sata/data/wikipedia/text/categories_and_templates2.txt";

		String dict = "/media/sata/data/wikipedia/text/categories_dictionary1.txt";
		String dict_expanded = "/media/sata/data/wikipedia/text/categories_expanded.txt";

		int fields[] = { 2 };
		WikiCategoryNavigator navigator = new WikiCategoryNavigator(dict,
				dict_expanded, 1, fields, "\t", "\"", "\t");

		// navigator.generateCategoryBlackList();

		// navigator.expandCategoriesFile(path, "\t", "\"", 6);
		// navigator.generateCategoryExpandedList(4);
		// WikiCategoryNavigator.printCategoryList(path);

		navigator.expandCategoriesTemplates(path, "\t", "\"", 3);

		// WikiCategoryNavigator.createCategoryDictionary(path);

	}

}
